package inabit.crisp.inference;

import inabit.base.RuleBase;
import inabit.base.WorkingMemory;
import inabit.data.FireableRule;
import inabit.data.Rule;
import inabit.data.Variable;
import inabit.data.expression.ConsequentExpression;
import inabit.data.expression.Expression;
import inabit.inference.ForwardEngine;
import inabit.utils.ExpressionStringFormat;
import inabit.utils.RuleStringFormat;

import java.util.ArrayList;
import java.util.List;
/**A implementation of the forward engine
 * @author Rafael Rocha*/
public class ForwardEngineImpl extends ForwardEngine{


	private RuleStringFormat ruleFormat;
	private ExpressionStringFormat expFormat;
	
	public ForwardEngineImpl() {
		setRuleStringFormat(new RuleStringFormat());
	}
	public void setRuleStringFormat(RuleStringFormat format){
		this.ruleFormat = format;
		expFormat = format.getExpressionFormat();
	}
	
	protected String getInnerNodeLabel(Rule r) {
		return r.getID() + " : " + expFormat.format(r.getPrecedent());
	}
	
	protected String getConsequentString(ConsequentExpression consequent) {
		return expFormat.format(consequent);
	}
	

	protected String getRootNodeLabel() {
		return ">>>";
	}
	private boolean unresolvedConsequent(Expression consequent, WorkingMemory wm) {
		for(Variable var : consequent.getReferencedVariables(wm)) {
			if(var.getValue() == null) {
				return true;
			}
		}
		return false;
	}
	@Override
	public List<FireableRule> conflictSet(RuleBase rb, WorkingMemory wm) {
		List<FireableRule> conflictSet = new ArrayList<FireableRule>();
		for(FireableRule rule : rb.getAllFireableRules()){
			
			if(!rule.hasFired()) {
				
				Double eval = rule.evaluate(wm);
				if(eval != null && eval > Double.MIN_VALUE) {
					
					conflictSet.add(rule);
				}
			}
		}
		return conflictSet;
	}

	@Override
	public FireableRule resolveSet(List<FireableRule> conflictSet, WorkingMemory wm) {
		for(FireableRule rule : conflictSet) {
			if(!unresolvedConsequent(rule.getConsequent(), wm)) {
				return rule;
			}
		}
		return conflictSet.get(0);
	}

}
